// csharp_demo.cs - SecureConfig命令行工具的C#演示程序
// 使用前安装 Newtonsoft.Json 包: dotnet add package Newtonsoft.Json

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace SecureConfigDemo
{
    class Program
    {
        // 终端颜色代码
        private static class Colors
        {
            public const string Cyan = "\u001b[36m";
            public const string Yellow = "\u001b[33m";
            public const string Green = "\u001b[32m";
            public const string Red = "\u001b[31m";
            public const string Reset = "\u001b[0m";
        }

        // 为文本添加颜色
        private static string Colorize(string text, string color)
        {
            return $"{color}{text}{Colors.Reset}";
        }

        static async Task Main(string[] args)
        {
            // 计时开始
            var startTime = DateTime.Now;

            // 设置主密钥环境变量
            // 实际使用时请替换为您的真实密钥
            Environment.SetEnvironmentVariable("SECURECONFIGMASTERKEY", "your_master_key_here");

            Console.WriteLine(Colorize("\n===== 第一部分: 常规加解密操作 =====", Colors.Cyan));

            try
            {
                // 1. 创建 json 配置文件
                var jsonName = "demo_json";
                Console.WriteLine($"创建 json 配置文件: {jsonName}");
                var result = await RunSecureCommand("create", jsonName, "--type", "json", "--force");
                PrintResult("创建 json 配置", result);

                // 2. set-value 仅支持 json
                Console.WriteLine($"设置 json 配置的值: {jsonName} app.version = 2.0.0");
                result = await RunSecureCommand("set-value", jsonName, "app.version", "2.0.0");
                PrintResult("设置 json 配置值", result);

                // 3. get-value 仅支持 json
                Console.WriteLine($"获取 json 配置的值: {jsonName} app.version");
                result = await RunSecureCommand("get-value", jsonName, "app.version");
                PrintResult("获取 json 配置值", result);

                // 4. 创建 text 文件
                var textName = "demo_text";
                Console.WriteLine($"创建 text 文件: {textName}");
                result = await RunSecureCommand("create", textName, "--type", "text", "--force");
                PrintResult("创建 text 文件", result);

                // 5. 保存明文内容到 text 文件（直接写入文件）
                var textPath = Path.Combine("configs", $"{textName}.txt");
                try
                {
                    Directory.CreateDirectory(Path.GetDirectoryName(textPath));
                    File.WriteAllText(textPath, "Hello, SecureConfig!\n这是一个文本文件。", Encoding.UTF8);
                    Console.WriteLine($"已写入明文内容到 {textPath}");
                }
                catch (Exception ex)
                {
                    Console.WriteLine(Colorize($"写入文件失败: {ex.Message}", Colors.Red));
                    return;
                }

                // 6. 加密 text 文件
                Console.WriteLine($"加密 text 文件: {textName}");
                result = await RunSecureCommand("encrypt", textName, "--type", "text");
                PrintResult("加密 text 文件", result);

                // 7. 解密 text 文件
                Console.WriteLine($"解密 text 文件: {textName}");
                result = await RunSecureCommand("decrypt", textName, "--type", "text");
                PrintResult("解密 text 文件", result);

                // 8. 创建 binary 文件
                var binaryName = "demo_bin";
                Console.WriteLine($"创建 binary 文件: {binaryName}");
                result = await RunSecureCommand("create", binaryName, "--type", "binary", "--force");
                PrintResult("创建 binary 文件", result);

                // 9. 保存明文内容到 binary 文件（写入二进制数据）
                var binaryPath = Path.Combine("configs", $"{binaryName}.bin");
                try
                {
                    Directory.CreateDirectory(Path.GetDirectoryName(binaryPath));
                    File.WriteAllBytes(binaryPath, new byte[] { 0, 1, 2, 3, 4, 5, 6, 7 });
                    Console.WriteLine($"已写入明文内容到 {binaryPath}");
                }
                catch (Exception ex)
                {
                    Console.WriteLine(Colorize($"写入文件失败: {ex.Message}", Colors.Red));
                    return;
                }

                // 10. 加密 binary 文件
                Console.WriteLine($"加密 binary 文件: {binaryName}");
                result = await RunSecureCommand("encrypt", binaryName, "--type", "binary");
                PrintResult("加密 binary 文件", result);

                // 11. 解密 binary 文件
                Console.WriteLine($"解密 binary 文件: {binaryName}");
                result = await RunSecureCommand("decrypt", binaryName, "--type", "binary");
                PrintResult("解密 binary 文件", result);

                Console.WriteLine(Colorize("\n===== 第二部分: 原地加解密操作 (使用 --inplace 参数) =====", Colors.Cyan));

                // 12. 创建原地加密演示文件
                var inplaceName = "inplace_demo";
                var jsonPath = Path.Combine("configs", $"{inplaceName}.json");
                var backupPath = Path.Combine("configs", $"{inplaceName}_backup.json");

                Console.WriteLine($"创建原地加密演示 json 文件: {inplaceName}");
                result = await RunSecureCommand("create", inplaceName, "--type", "json", "--force");
                PrintResult("创建原地加密演示文件", result);

                // 13. 设置演示文件内容
                Console.WriteLine($"设置演示文件值: {inplaceName}");
                await RunSecureCommand("set-value", inplaceName, "demo.name", "原地加密演示");
                result = await RunSecureCommand("set-value", inplaceName, "demo.description", "这是一个测试原地加密功能的文件");

                // 14. 解密后备份原始明文文件（用于对比）
                result = await RunSecureCommand("decrypt", inplaceName, "--type", "json");
                try
                {
                    File.Copy(jsonPath, backupPath, true);
                    Console.WriteLine($"已备份明文文件到 {backupPath}");
                }
                catch (Exception ex)
                {
                    Console.WriteLine(Colorize($"备份文件失败: {ex.Message}", Colors.Red));
                }
                PrintResult("设置演示文件值", result);

                // 15. 原地加密
                Console.WriteLine($"原地加密文件: {inplaceName} (使用 --inplace 参数)");
                result = await RunSecureCommand("encrypt", inplaceName, "--type", "json", "--inplace");
                PrintResult("原地加密", result);

                // 16. 验证原地加密结果
                var encryptedJsonExists = File.Exists(Path.Combine("configs", $"{inplaceName}.json.enc"));
                var originalJsonExists = File.Exists(jsonPath);
                Console.WriteLine($"加密文件 ({inplaceName}.json.enc) 是否存在? {encryptedJsonExists}");
                Console.WriteLine($"原始文件 ({inplaceName}.json) 是否存在? {originalJsonExists} (原地加密，应该存在)");

                // 17. 原地解密
                Console.WriteLine($"原地解密文件: {inplaceName} (使用 --inplace 参数)");
                result = await RunSecureCommand("decrypt", inplaceName, "--type", "json", "--inplace");
                PrintResult("原地解密", result);

                // 18. 验证文件是否相同
                bool areFilesIdentical = false;
                try
                {
                    var file1Content = File.ReadAllBytes(jsonPath);
                    var file2Content = File.ReadAllBytes(backupPath);
                    areFilesIdentical = file1Content.SequenceEqual(file2Content);
                }
                catch (Exception ex)
                {
                    Console.WriteLine(Colorize($"比较文件时出错: {ex.Message}", Colors.Red));
                }

                Console.WriteLine($"原地加解密后的文件与原始文件是否相同? {areFilesIdentical}");

                // 19. 清理演示文件
                Console.WriteLine(Colorize("\n===== 清理演示文件 =====", Colors.Cyan));
                var filesToDelete = new List<string> { jsonName, textName, binaryName, inplaceName };

                foreach (var name in filesToDelete)
                {
                    Console.WriteLine($"删除文件: {name}");
                    await RunSecureCommand("delete", name, "--type", "json");
                }

                if (File.Exists(backupPath))
                {
                    try
                    {
                        File.Delete(backupPath);
                        Console.WriteLine($"已删除备份文件: {backupPath}");
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(Colorize($"删除备份文件失败: {ex.Message}", Colors.Red));
                    }
                }

                // 20. 演示 get-value/set-value 仅支持 json 的限制
                Console.WriteLine(Colorize("\n===== 演示 get-value/set-value 仅支持 json 的限制 =====", Colors.Cyan));

                Console.WriteLine($"尝试对 text 文件使用 get-value (应报错)");
                try
                {
                    result = await RunSecureCommand("get-value", textName, "app.version", "--type", "text");
                }
                catch (Exception ex)
                {
                    result = new JObject
                    {
                        ["status"] = "error",
                        ["message"] = ex.Message
                    };
                }
                PrintResult("get-value 用于 text 类型", result);

                Console.WriteLine($"尝试对 binary 文件使用 get-value (应报错)");
                try
                {
                    result = await RunSecureCommand("get-value", binaryName, "app.version", "--type", "binary");
                }
                catch (Exception ex)
                {
                    result = new JObject
                    {
                        ["status"] = "error",
                        ["message"] = ex.Message
                    };
                }
                PrintResult("get-value 用于 binary 类型", result);

                // 计算总耗时
                var endTime = DateTime.Now;
                var totalTime = (endTime - startTime).TotalSeconds;
                Console.WriteLine(Colorize($"\n全部演示完成，总耗时: {totalTime:F2} 秒", Colors.Green));
            }
            catch (Exception ex)
            {
                Console.WriteLine(Colorize($"执行程序时发生错误: {ex.Message}", Colors.Red));
                Console.WriteLine(ex.StackTrace);
            }
        }

        /// <summary>
        /// 运行SecureConfig命令并返回结果
        /// </summary>
        private static async Task<JObject> RunSecureCommand(string command, params string[] args)
        {
            var processInfo = new ProcessStartInfo
            {
                FileName = "secureconfig",
                Arguments = $"{command} -f json {string.Join(" ", args)}",
                RedirectStandardOutput = true,
                RedirectStandardError = true,
                UseShellExecute = false,
                CreateNoWindow = true
            };

            Console.WriteLine(Colorize($"执行命令: secureconfig {command} -f json {string.Join(" ", args)}", Colors.Yellow));

            try
            {
                using (var process = Process.Start(processInfo))
                {
                    // 异步读取输出和错误
                    var outputTask = process.StandardOutput.ReadToEndAsync();
                    var errorTask = process.StandardError.ReadToEndAsync();
                    
                    await process.WaitForExitAsync();
                    
                    var output = await outputTask;
                    var error = await errorTask;

                    if (process.ExitCode != 0)
                    {
                        Console.WriteLine(Colorize($"命令执行失败 (退出码 {process.ExitCode}):", Colors.Red));
                        if (!string.IsNullOrEmpty(error))
                        {
                            Console.WriteLine(error);
                        }

                        // 检查错误输出中是否包含JSON
                        if (!string.IsNullOrEmpty(output) || !string.IsNullOrEmpty(error))
                        {
                            try
                            {
                                string content = !string.IsNullOrEmpty(output) ? output : error;
                                int jsonStart = content.IndexOf('{');
                                if (jsonStart >= 0)
                                {
                                    content = content.Substring(jsonStart);
                                    return JObject.Parse(content);
                                }
                            }
                            catch
                            {
                                // 如果无法解析JSON，返回错误对象
                            }
                        }

                        return new JObject
                        {
                            ["status"] = "error",
                            ["message"] = $"命令执行失败，退出码: {process.ExitCode}"
                        };
                    }

                    // 查找JSON开始的位置，处理可能存在的非JSON前缀
                    int start = output.IndexOf('{');
                    if (start >= 0)
                    {
                        output = output.Substring(start);
                    }

                    return JObject.Parse(output);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(Colorize($"执行命令时出现异常: {ex.Message}", Colors.Red));
                return new JObject
                {
                    ["status"] = "error",
                    ["message"] = $"执行命令异常: {ex.Message}"
                };
            }
        }

        /// <summary>
        /// 打印结果
        /// </summary>
        private static void PrintResult(string title, JObject result)
        {
            Console.WriteLine(Colorize($"\n==== {title} ====", Colors.Cyan));
            if (result.TryGetValue("status", out var status) && status.ToString() == "success")
            {
                Console.WriteLine(result.ToString(Formatting.Indented));
            }
            else
            {
                string message = result.TryGetValue("message", out var msg) ? msg.ToString() : "未知错误";
                Console.WriteLine(Colorize($"失败: {message}", Colors.Red));
            }
        }
    }
}

/*
使用方法:
1. 确保已安装SecureConfig工具
2. 确保已安装.NET SDK
3. 创建项目: dotnet new console -o SecureConfigDemo
4. 复制此文件到项目中，替换Program.cs
5. 安装所需包: dotnet add package Newtonsoft.Json
6. 编译并运行: dotnet run
*/ 